package spring.cloud.tasks.tasks_manager;


import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import spring.cloud.tasks.common.curator.Curator;
import spring.cloud.tasks.common.curator.CuratorFactory;
import spring.cloud.tasks.common.curator.CuratorInfo;
import spring.cloud.tasks.tasks_manager.domain.Namespace;
import spring.cloud.tasks.tasks_manager.dto.NamespaceDto;
import spring.cloud.tasks.tasks_manager.dto.ZooKeeperDto;
import spring.cloud.tasks.tasks_manager.service.NamespaceDtoService;
import spring.cloud.tasks.tasks_manager.service.ZooKeeperDtoService;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 配置端+调度器+执行器 尽量性能优化到极致。add by huihui@2022.09.13 11.54
 * 从内存占用率 本地日志写占用时间 网络IO方面入手，极致的算法。
 * 每个地方都满足o(1) o(x) o(n) 时间或者空间复杂度。
 */
@Configuration
@Slf4j
public class BootStrap {
    public static final ConcurrentHashMap<String, Curator> nameSpaceToCuratorMap = new ConcurrentHashMap<String, Curator>();
    public static final CopyOnWriteArrayList allowScheduledNamespaceList = new CopyOnWriteArrayList<>();
    private static final ConcurrentHashMap<String, TasksManager> nameSpaceToTaskManagerMap = new ConcurrentHashMap<>();
    private final ReentrantLock lock = new ReentrantLock();
    @Resource
    private ZooKeeperDtoService zooKeeperDtoService;
    @Resource
    private NamespaceDtoService namespaceDtoService;
    private ExecutorService executorService;
    private ScheduledExecutorService scheduledExecutorService;

    @PostConstruct
    public void start() throws Exception {
        init();
    }

    @PreDestroy
    public void stop() throws Exception {
        destroy();
    }

    public void init() {
        //启动一个异步的线程 进行任务调度
        executorService = Executors.newSingleThreadExecutor();
        scheduledExecutorService = Executors.newScheduledThreadPool(1);
        refresh();
    }

    private void refresh() {
        scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                try {
                    boolean tryLock = lock.tryLock(10, TimeUnit.SECONDS);
                    if (tryLock) {
                        refresh();//避免等的时间太长
                        try {
                            refreshAllowScheduledNamespaceListFromDatabse();
                            refreshAllowScheduledNamespaceList();
                        } catch (Exception e) {
                            log.error("refresh RegCenter error", e);
                        }
                        lock.unlock();
                    }
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
        }, 5, TimeUnit.SECONDS);
    }

    @PreDestroy
    public void destroy() {
        if (executorService != null) {
            executorService.shutdown();//
        }
        Set<Map.Entry<String, Curator>> entrySet = nameSpaceToCuratorMap.entrySet();
        for (Map.Entry<String, Curator> entry : entrySet) {
            String nameSpace = entry.getKey();
            nameSpaceToCuratorMap.remove(nameSpace);
            Curator curator = entry.getValue();
            curator.close();
        }
    }

    private void refreshAllowScheduledNamespaceListFromDatabse() {
        allowScheduledNamespaceList.clear();
        allowScheduledNamespaceList.add("test");
    }

    private void refreshAllowScheduledNamespaceList() {
        Set<String> keySet = nameSpaceToTaskManagerMap.keySet();
        for (String namespaceKey : keySet) {
            if (!allowScheduledNamespaceList.contains(namespaceKey)) {
                closeNamespaceTasksManagerAndCurator(namespaceKey);
            }
        }
        for (Object o : allowScheduledNamespaceList.toArray()) {
            String namespaceKey = (String) o;
            TasksManager taskManager = nameSpaceToTaskManagerMap.get(namespaceKey);//==null表示在map中key可能存在但值为空或者不存在两种情况
            if (taskManager == null) {
                createNamespaceCuratorAndTasksManager(namespaceKey);
            }
        }


    }

    private void createNamespaceCuratorAndTasksManager(String namespaceKey) {
        NamespaceDto namespaceDto = namespaceDtoService.getNamespaceDto(namespaceKey);
        ZooKeeperDto zooKeeperDto = zooKeeperDtoService.selectByZooKeeperKey(namespaceDto.getZookeeperKey());
        try {
            CuratorInfo curatorInfo = new CuratorInfo();
            curatorInfo.setAddressList(zooKeeperDto.getAddressList());
            curatorInfo.setDigest(zooKeeperDto.getDigest());
            curatorInfo.setNamespaceKey(namespaceKey);
            Curator curator = CuratorFactory.getCurator(curatorInfo, CuratorFactory.shortTime_true);
            if (curator == null) {
                log.warn("连接命名空间失败:" + namespaceKey);
                return;
            }
            TasksManager taskManager = null;
            try {
                taskManager = new TasksManager(curator, namespaceKey);
                taskManager.start();
                if (nameSpaceToTaskManagerMap.putIfAbsent(namespaceKey, taskManager) != null) {
                    log.info("命名空间:" + namespaceKey + "任务调度器已经存在" + ",关闭当前任务调度器");
                    try {
                        taskManager.stopWithCuratorFramework();
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                    }
                } else {
                    log.info("命名空间:" + namespaceKey + "任务调度器创建成功:");
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                if (taskManager != null) {
                    try {
                        taskManager.stop();
                    } catch (Exception e2) {
                        log.error(e2.getMessage(), e2);
                    }
                }
                curator.close();
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    private void closeNamespaceTasksManagerAndCurator(String namespaceKey) {
        try {
            TasksManager tasksManager = nameSpaceToTaskManagerMap.remove(namespaceKey);
            if (tasksManager != null) {
                tasksManager.stopWithCuratorFramework();
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        try {
            Curator curator = nameSpaceToCuratorMap.remove(namespaceKey);
            if (curator != null) {
                curator.close();
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    private void closeNotExistsnameSpace(List<Namespace> nameSpaceList, List<NamespaceDto> nameSpaceDtoList) {
        if (nameSpaceList == null) {
            return;
        }
        Iterator<Namespace> iterator = nameSpaceList.iterator();
        while (iterator.hasNext()) {
            Namespace $nameSpace = iterator.next();
            String nameSpace = $nameSpace.getNamespaceKey();
            boolean include = false;
            if (nameSpaceDtoList != null) {
                for (NamespaceDto nameSpaceDto : nameSpaceDtoList) {
                    if (nameSpace.equals(nameSpaceDto.getNamespaceKey())) {
                        include = true;
                        break;
                    }
                }
            }
            //关闭不存在的
            if (!include) {
                synchronized (nameSpace.intern()) {
                    iterator.remove();
                    closeNamespaceTasksManagerAndCurator(nameSpace);
                }
            }
        }
    }

}